package com.fan.base.exception;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.util.IOUtils;
import com.fan.base.enums.DateStyle;
import com.fan.base.utils.DateUtils;

public class ExceptionUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger("exception logger");

	/**
	 * 这个异常信息需要保存或者传递时使用，目前先定义出来
	 * 
	 * @return
	 */
	public static String createExceptionId() {
		return DateUtils.toString(new Date(), DateStyle.MMDDHHMISSSSS)
				+ (int) (Math.random() * 1000);
	}

	/**
	 * 根据不同的异常信息展示不同的异常提示
	 * @param t
	 * @param message
	 * @return
	 */
	public static RuntimeException handleException(Throwable t, String message) {
		Object e = null;
		if (t instanceof BusinessException) {
			logException((BusinessException)t, message);
			return (BusinessException) e;
		} else if (t instanceof SystemException) {
			logException((SystemException)t, message);
			return (SystemException)e;
		} else {
			//暂时来说所有除了已定义的业务异常和系统异常之外的异常统一转换为系统异常进行后续处理。
			//如果有后续异常，比如非运行时异常要特化处理的可以再加分支进行处理
			SystemException se = StringUtils.isBlank(message) ? new SystemException(t) : new SystemException(message, t);
			logException(se, message);
			return se;
		}
	}

	private static void logException(BusinessException e, String message) {
		if (StringUtils.isNotBlank(message)) {
			LOGGER.error("发生异常，自定义异常信息：" + message);
		} else {
			LOGGER.error("发生业务异常：" + e.getMessage());
		}
		LOGGER.error("异常堆栈： \n" + getRootCauseStackTrace(e));
	}
	
	private static void logException(SystemException e, String message) {
		if (StringUtils.isNotBlank(message)) {
			LOGGER.error("发生异常，自定义异常信息：" + message);
		} else {
			LOGGER.error("发生系统异常：" + e.getMessage());
		}
		LOGGER.error("异常堆栈： \n" + getRootCauseStackTrace(e));
	}
	/**
	 * 获取最开始抛出异常信息的堆栈轨迹信息
	 * 
	 * @param ex
	 * @return
	 */
	public static String getRootCauseStackTrace(Exception ex) {
		Throwable rootException = getExceptionRootCause(ex);
		return getExceptionStackTrace(rootException);
	}

	/**
	 * 获取最开始抛出异常的异常对象
	 * 
	 * @param ex
	 * @return
	 */
	private static Throwable getExceptionRootCause(Throwable ex) {
		return ex.getCause() == null ? ex : getExceptionRootCause(ex.getCause());
	}

	/**
	 * 获取抛出异常信息的堆栈轨迹信息
	 * 
	 * @param t
	 * @return
	 */
	private static String getExceptionStackTrace(Throwable t) {
		String exceptionStackTrace = null;
		if (t == null) {
			return exceptionStackTrace;
		}
		//获取异常的堆栈轨迹信息，输出到一个字符串流中
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		try {
			t.printStackTrace(pw);
			exceptionStackTrace = sw.toString();
		} finally {
			IOUtils.close(sw);
			IOUtils.close(pw);
		}
		return exceptionStackTrace;
	}
}
